﻿#region - 版 本 注 释 -
/*----------------------------------------------------------------
 * 版权所有 (c) 2024   保留所有权利。
 * CLR版本：4.0.30319.42000
 * 机器名称：DESKTOP-GLJ2Q8J
 * 公司名称：
 * 命名空间：AutoCAD.EntityTool
 * 唯一标识：b67ef309-d904-4480-8f46-f67bd9e5dc6b
 * 文件名：PointTools
 * 当前用户域：DESKTOP-GLJ2Q8J
 * 
 * 创建者：Guo-79991
 * 电子邮箱：799919859@qq.com
 * 创建时间：2024/7/15 11:58:06
 * 版本：V1.0.0
 *
 * 功能描述(Description):
 * 参考文档(Reference):
 * 数据表(Tables):
 * 作者(Author):Guo
 *
 * ----------------------------------------------------------------
 * 修改人：
 * 时间：
 * 修改说明：
 *
 * 版本：V1.0.1
 *----------------------------------------------------------------*/
#endregion - 版 本 注 释 -

namespace AutoCAD.EntityTools
{
    /// <summary>
    /// PointTools 的摘要说明
    /// </summary>
    public static class PointTools
    {
        /// <summary>
        /// 将3D点转换为2D点，忽略Z坐标
        /// </summary>
        /// <param name="point3d">要转换的3D点</param>
        /// <returns>转换后的2D点</returns>
        public static Point2d Point3dToPoint2d(this Point3d point3d) => new Point2d(point3d.X, point3d.Y);
        /// <summary>
        /// 将2D点转换为3D点
        /// </summary>
        /// <param name="point2d">要转换的2D点</param>
        /// <returns>转换后的3D点</returns>
        public static Point3d Point2dToPoint3d(this Point2d point2d) => new Point3d(point2d.X, point2d.Y, 0);
        /// <summary>
        /// 获取2D点的中心点
        /// </summary>
        /// <param name="point2d">要获取中心的2D点</param>
        /// <returns>中心点</returns>
        public static Point2d GetPoint2dCenter(this Point2d point2d) => new Point2d(point2d.X, point2d.Y) / 2;
        /// <summary>
        /// 获取3D点的中心点
        /// </summary>
        /// <param name="point3d">要获取中心的3D点</param>
        /// <returns>中心点</returns>
        public static Point3d GetPoint3dCenter(this Point3d point3d) => new Point3d(point3d.X, point3d.Y, 0) / 2;
        /// <summary>
        /// 获取两个点之间的中心点
        /// </summary>
        /// <param name="startPoint">起点</param>
        /// <param name="endPoint">终点</param>
        /// <returns>中点</returns>
        public static Point3d GetCenterPointInTwoPointBetween(this Point3d startPoint, Point3d endPoint)
    => new Point3d(startPoint.X + endPoint.X, startPoint.Y + endPoint.Y, 0) / 2;
        /// <summary>
        /// 获取从起点到终点的向量坐标，该向量的起点是原点。
        /// </summary>
        /// <param name="startPoint">起点坐标。</param>
        /// <param name="endPoint">终点坐标。</param>
        /// <returns>一个Point3d对象，表示从起点到终点的向量坐标，Z坐标为0。</returns>
        /// <remarks>此方法返回的坐标并不是终点坐标，而是从起点到终点的向量坐标。如果需要得到终点的绝对坐标，应该直接返回endPoint。</remarks>
        public static Point3d GetPointArrivePointCoordinate(this Point3d startPoint, Point3d endPoint)
            => new Point3d(startPoint.X + endPoint.X, startPoint.Y + endPoint.Y, 0);
        /// <summary>
        /// 获取两个3d点之间的中心点
        /// </summary>
        /// <param name="start">起点</param>
        /// <param name="end">终点</param>
        /// <returns>中心点</returns>
        public static Point3d GetTwoPoint3dCenter(this Point3d start, Point3d end) => new Point3d(start.X + end.X, start.Y + end.Y, 0) / 2;
        /// <summary>
        /// 获取两个2d点之间的中心点
        /// </summary>
        /// <param name="start">起点</param>
        /// <param name="end">终点</param>
        /// <returns>中心点</returns>
        public static Point2d GetTwoPoint2dCenter(this Point2d start, Point2d end) => new Point2d(start.X + end.X, start.Y + end.Y) / 2;
        /// <summary>
        /// 获取与给定点指定角度和距离的点
        /// </summary>
        /// <param name="point"></param>
        /// <param name="angle"></param>
        /// <param name="dist"></param>
        /// <returns></returns>
        public static Point3d PolarPoint(this Point3d point, double angle, double dist) => new Point3d(point.X + dist * Math.Cos(angle), point.Y + dist * Math.Sin(angle), point.Z);
        /// <summary>
        /// 3d转2d
        /// </summary>
        /// <param name="point3d">3d点</param>
        /// <returns></returns>
        public static Point2d Point3dConvertToPoint2d(this Point3d point3d) => new Point2d(point3d.X, point3d.Y);
        /// <summary>
        /// 判断三点是否在同一条直线上
        /// </summary>
        /// <param name="firstPoint">第一个点</param>
        /// <param name="secondPoint">第二个点</param>
        /// <param name="thirdPoint">第三个点</param>
        /// <returns>是否在同一条直线上</returns>
        public static bool IsOnOneLine(this Point3d firstPoint, Point3d secondPoint, Point3d thirdPoint)
        {
            Vector3d v21 = secondPoint.GetVectorTo(firstPoint);
            Vector3d v23 = secondPoint.GetVectorTo(thirdPoint);
            if (v21.GetAngleTo(v23) == 0 || v21.GetAngleTo(v23) == Math.PI)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 计算两点中间点
        /// </summary>
        public static Point3d MidPoint(this Point3d p1, Point3d p2)
        {
            return new Point3d(
                (p1.X + p2.X) / 2,
                (p1.Y + p2.Y) / 2,
                (p1.Z + p2.Z) / 2);
        }

        // 判断两个点是否相等，考虑小数点误差
        public static bool ArePointsEqual(this Point3d p1, Point3d p2, double epsilon)
        {
            return Math.Abs(p1.X - p2.X) < epsilon && Math.Abs(p1.Y - p2.Y) < epsilon;
        }
        /// <summary>
        /// 获得point X 方向与point2的角度
        /// </summary>
        /// <param name="point1">点1</param>
        /// <param name="point2">点2</param>
        /// <returns></returns>
        public static double GetAngleToXAxis(this Point3d point1, Point3d point2)
        {
            var vector1 = point1.GetVectorTo(point1 + Vector3d.XAxis * 1);
            var vector2 = point1.GetVectorTo(point2);
            return (vector1.GetAngleTo(vector2)).DegreeToAngle();
        }
        public static Point3d GetCenterPointInTwoPointBetweenInt(this Point3d startPoint, Point3d endPoint)
=> new Point3d((int)startPoint.X + (int)endPoint.X, (int)startPoint.Y + (int)endPoint.Y, 0) / 2;
        /// <summary>
        /// 如果距离小于等于指定的误差（tolerance），则判定这两个点相等
        /// </summary>
        /// <param name="point1">点1</param>
        /// <param name="point2">点2</param>
        /// <param name="tolerance">误差</param>
        /// <returns>两个点是否相等</returns>
        public static bool ArePointEquals(this Point3d point1, Point3d point2, double tolerance) => point1.DistanceTo(point2) <= tolerance;

        /// <summary>
        /// <summary>
        /// 检查四个点是否共面
        /// </summary>
        public static bool PointsAreCoplanar(Point3d[] points)
        {
            if (points.Length < 4) return true;

            Vector3d v1 = points[1] - points[0];
            Vector3d v2 = points[2] - points[0];
            Vector3d normal = v1.CrossProduct(v2).GetNormal();

            double distance = normal.DotProduct(points[3] - points[0]);
            return distance.IsZero(0.001);
        }


        /// <summary>
        /// 点和点相加
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <returns></returns>
        public static Point3d Add(this Point3d p1, Point3d p2) => new Point3d(p1.X + p2.X, p1.Y + p2.Y, p1.Z + p2.Z);
        /// <summary>
        /// 点坐标相减（返回新点）
        /// </summary>
        /// <param name="p1">被减点</param>
        /// <param name="p2">减点</param>
        /// <returns>返回坐标差的新点</returns>
        public static Point3d Sub(this Point3d p1, Point3d p2) => new Point3d(
                p1.X - p2.X,
                p1.Y - p2.Y,
                p1.Z - p2.Z);



        /// <summary>
        /// 点和点相加
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <returns></returns>
        public static Point2d Add(this Point2d p1, Point2d p2) => new Point2d(p1.X + p2.X, p1.Y + p2.Y);
        /// <summary>
        /// 点坐标相减（返回新点）
        /// </summary>
        /// <param name="p1">被减点</param>
        /// <param name="p2">减点</param>
        /// <returns>返回坐标差的新点</returns>
        public static Point2d Sub(this Point2d p1, Point2d p2) => new Point2d(
                p1.X - p2.X,
                p1.Y - p2.Y);

        /// <summary>
        /// 测量两点之间的距离
        /// </summary>
        /// <param name="point1">第一个点</param>
        /// <param name="point2">第二个点</param>
        /// <returns>两点之间的距离（单位与当前图纸一致）</returns>
        public static double MeasureDistance(Point3d point1, Point3d point2)
        {
            return point1.DistanceTo(point2);
        }
    }
}
